#include"include.h"

/*
 * What will main be doing? At the high level main will serve as an interface
 * between whatever gui we have and the client(s). If you like the MVC design
 * the main method and related eventloop acts a lot like a Controller.
 *
 * At a lower level that means we'll be constructing a client "object",
 * putting it into its EventLoop, and then go into our own EventLoop waiting
 * for user interaction. Each of these will be passed to the client and it'll
 * deal with them appropriately. The client(s) will be in their own threads.
 * In order to tell the client what object the user is interacting with both
 * the client and this will need pointers to the torrent lists. Because the 
 * torrent will be accessed from multiple threads we'll build a semaphore
 * straight into the torrent_t itself. Hopefully that works.
 */


list_t *clients;
pthread_t client_pthread;

pthread_t diskio_pthread;

cli_t *cli;


void ctrlCInterrupt()
{
   loggerLog(LOG_INFO, "Exiting diskio...\n");
   tdiskExitAndCleanup(diskman);
   pthread_join(diskio_pthread, NULL);

   loggerLog(LOG_INFO, "Exiting all clients....\n");
   for(resetList(clients);!endList(clients);)
   {
      client_t *c = getObject(clients);
      clientExit(c);
      pthread_join(client_pthread, NULL);
   }
   clearListAndFreeElementsNP(clients);
   free(clients);

   cliShutdown(cli);

   configExit(conf);

   loggerExit();
   exit(1);
}

int main(int argc, char **argv)
{
 /*  if(argc == 1)
   {
      printf("Usage: %s <torrent file>\n", argv[0]);
      return 0;
   }*/

   struct timeval tim;
   gettimeofday(&tim, NULL);
   srand(tim.tv_usec * getpid());

   struct stat st;
   if(stat("config.ini", &st) != 0)
   {
      fprintf(stderr, "You must have a config.ini file to use this program.\n");
      exit(1);
   }

   conf = configInit("config.ini");

   //loggerInit();
   loggerEnableStdout(configGetInt(conf, "LogStdout"));
   loggerEnableStderr(configGetInt(conf, "LogStderr"));
   char *logLevel = strtolower(configGetString(conf, "LogLevel"));
   loggerSetLevel((strcmp(logLevel, "debug") == 0) ? LOG_DEBUG
                 :(strcmp(logLevel, "info") == 0) ? LOG_INFO
                 :(strcmp(logLevel, "warning") == 0) ? LOG_WARN
                 :(strcmp(logLevel, "error") == 0) ? LOG_ERR
                 : LOG_NONE);
   char *logFile = configGetString(conf, "LogFile");
   if(logFile != NULL)
   {
      FILE *logf = fopen(logFile, "a");
      if(logf == NULL)
         loggerLog(LOG_WARN, "Could not write to log file %s.\n", logFile);
      else
         loggerEnableFile(logf);
   }

   clients = createList();

   signal(SIGINT, ctrlCInterrupt);

   uint16_t port = configGetInt(conf, "Port");
   if(port <= 0)
   {
      loggerLog(LOG_ERR,
         "Port was <= 0. Please specify a valid port in config.ini.\n");
   }

   client_t *c = clientInit(port);
   addObject(clients, c);

   diskman = tdiskInit();

   cli = cliInit(c);
   
   if((pthread_create(&client_pthread, NULL,
      (void * (*)(void *))&clientEventLoop, (void *)c)))
   {
      loggerLog(LOG_ERR, "Could not create client thread.\n");
      ctrlCInterrupt();
   }


   if((pthread_create(&diskio_pthread, NULL, (void * (*)(void *))&tdiskRun,
      (void *)diskman)))
   {
      loggerLog(LOG_ERR, "Could not create disk io thread.\n");
      ctrlCInterrupt();
   }

   if(argc == 2)
   {
      if(clientAddTorrentFile(c,argv[1]) == false)
         return 1;
      list_t *torrents = clientGetTorrents(c);
      resetList(torrents);
      clientStartTorrent(c, getObject(torrents));
   }

   // Initialize CLI
   cliRun(cli);
   
   // If the user does exit in CLI, cleanup everything
   ctrlCInterrupt();
   return 0;
}
